package com.xiaodou.mjf.web.xface.core.controller;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.Key;
import java.security.KeyFactory;
import java.security.spec.X509EncodedKeySpec;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.crypto.Cipher;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.ArrayUtils;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Maps;
import com.xiaodou.mjf.application.basic.service.SmsService;
import com.xiaodou.mjf.application.basic.utils.SequenceGenerator;
import com.xiaodou.mjf.application.core.manager.AccountManager;
import com.xiaodou.mjf.application.core.service.InvestCrowdControlService;
import com.xiaodou.mjf.application.core.service.InvestCrowdLimitService;
import com.xiaodou.mjf.application.core.service.InvestCrowdService;
import com.xiaodou.mjf.application.user.manager.MemberManager;
import com.xiaodou.mjf.application.user.manager.result.RegisterResult;
import com.xiaodou.mjf.application.user.service.MemberSecurityService;
import com.xiaodou.mjf.application.user.utils.MemberUtils;
import com.xiaodou.mjf.entity.basic.Sms;
import com.xiaodou.mjf.entity.core.Account;
import com.xiaodou.mjf.entity.core.InvestCrowd;
import com.xiaodou.mjf.entity.core.InvestCrowdControl;
import com.xiaodou.mjf.entity.core.InvestCrowdLimit;
import com.xiaodou.mjf.entity.core.NotesBook;
import com.xiaodou.mjf.entity.user.MemberSecurity;
import com.xiaodou.mjf.infrastructure.common.controller.ApiController;
import com.xiaodou.mjf.infrastructure.common.sms.SMSClient;
import com.xiaodou.mjf.infrastructure.common.utils.StringUtils;
import com.xiaodou.mjf.infrastructure.payment.RZContents;
import com.xiaodou.mjf.web.xface.common.ResultCode;
import com.xiaodou.mjf.web.xface.core.domain.InvestCrowdLimitVO;

/**
 * Created by Alvin on 2015/3/30.
 */
@Controller
@RequestMapping("v1/core")
public class InvestCrowdController extends ApiController {


	@Resource
	private SmsService smsService;

	@Resource
	private MemberSecurityService memberSecurityService;

	@Resource
	private MemberManager memberManager;

	@Resource
	private AccountManager accountManager;

	@Resource
	private InvestCrowdService investCrowdService;

	@Resource
	private InvestCrowdLimitService investCrowdLimitService;

	@Resource
	private InvestCrowdControlService investCrowdControleService;

	@RequestMapping("investCrowd/list")
	@ResponseBody
	public List<InvestCrowdLimit> list(HttpServletResponse response) {
		// 列表:
		List<InvestCrowdLimit> investCrowdLimits = investCrowdLimitService.findByStatus(0);
		response.setHeader("Access-Control-Allow-Origin", "*");
		return investCrowdLimits;
	}

	@RequestMapping(value = "investCrowd/info/{id}", method = RequestMethod.GET)
	@ResponseBody
	public InvestCrowdLimitVO info(@PathVariable("id") String id, HttpServletResponse response) {
		InvestCrowdLimitVO investCrowdLimitVO = new InvestCrowdLimitVO();
		// 详细信息:
		InvestCrowdLimit investCrowdLimit = investCrowdLimitService.get(id);
		String limitId = investCrowdLimit.getId();
		List<InvestCrowdControl> investCrowdControlList = investCrowdControleService.findByLimitId(limitId);

		investCrowdLimitVO.setInvestCrowdLimit(investCrowdLimit);
		investCrowdLimitVO.setInvestCrowdControlList(investCrowdControlList);

		response.setHeader("Access-Control-Allow-Origin", "*");
		return investCrowdLimitVO;
	}

	/**
	 * todo:众筹付款
	 *
	 * @param cid
	 *            渠道id
	 * @param type
	 *            投资类型 3 - 产品众筹 ；4 - 股权众筹
	 * @param crowdLimitId
	 *            众筹LimitId
	 * @param crowdControlId
	 *            众筹ControlId
	 * @param crowdLevel
	 *            众筹等级
	 * @param mobile
	 *            手机号
	 * @param code
	 *            验证码
	 * @param expectReturn
	 *            预计回报
	 * @param amount
	 *            投资金额
	 * @param returnURL
	 *            返回URL(绝对路径)
	 * @param request
	 * @param response
	 * @return
	 */
	@RequestMapping("investCrowd/pay")
	@ResponseBody
	public Map<String, Object> h5(String cid, int type, String crowdLimitId, String crowdControlId, int crowdLevel, String mobile, String code, String expectReturn, double amount, String returnURL, HttpServletRequest request, HttpServletResponse response) {
		response.setHeader("Access-Control-Allow-Origin", "*");
		String snpc = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath();
		Map<String, Object> result = success();
		DateTime now = new DateTime();

		// 获取众筹验证码
		Sms sms = smsService.findByPhone(mobile, 6);
		if (null == sms || !sms.getCode().equalsIgnoreCase(code)) {
			return failure(ResultCode.INVALID_VETIFY_CODE);
		}

		// 已经满额
		InvestCrowdLimit investCrowdLimit = investCrowdLimitService.get(crowdLimitId);
		InvestCrowdControl investCrowdControl = investCrowdControleService.get(crowdControlId);
		int levelUnit = investCrowdControl.getLevelUnit();
		if (null != investCrowdLimit) {
			int amountControlMethod = investCrowdLimit.getAmountControlMethod();
			if (0 == amountControlMethod) { // 0.按众筹项目份数控制
				if (null == investCrowdLimit || investCrowdLimit.getBalance() < levelUnit) {
					return failure(ResultCode.OVERFLOW);
				}
			} else if (1 == amountControlMethod) {// 1.按众筹项目分阶段份数控制
				// 数量判断
				if (null == investCrowdControl || investCrowdControl.getLevelBalance() < levelUnit) {
					return failure(ResultCode.OVERFLOW);
				}

			}
		}

		InvestCrowd investCrowd = new InvestCrowd();
		String crowdNo = investCrowdLimit.getCrowdNo();
		investCrowd.setCrowdNo(crowdNo);
		investCrowd.setCrowdLimitId(crowdLimitId);
		investCrowd.setCrowdControlId(crowdControlId);
		investCrowd.setCrowdLevel(crowdLevel);
		// 查询会员,没有会员则帮其注册
		MemberSecurity memberSecurity = memberSecurityService.getUserinfo(mobile);
		if (null != memberSecurity) {
			investCrowd.setMemberId(memberSecurity.getId());
			investCrowd.setMemberName(memberSecurity.getUserName());
		} else {
			RegisterResult registerResult = memberManager.register(mobile, mobile.substring(5, 11));
			SMSClient.sendNewUserMessage(mobile, "http://jr.mayfle.com");
			investCrowd.setMemberId(registerResult.getUid());
		}
		investCrowd.setType(type);
		investCrowd.setAmount(amount);
		investCrowd.setCount(1);
		investCrowd.setFee(0.0);
		investCrowd.setInvestDate(now.toDate());
		investCrowd.setChannelId(cid);
		investCrowd.setChannelSerial(SequenceGenerator.generateCrowd(SequenceGenerator.TYPE_CROWD, cid));
		investCrowd.setExpectReturnDate(now.toDate());
		investCrowd.setExpectReturn(expectReturn);
		investCrowd.setCrowdStatus(1);
		investCrowd.setStatus(0);
		investCrowd.setPayStatus(0);
		InvestCrowd investCrowdResult = investCrowdService.save(investCrowd);

		// TODO:以下开始支付
		Map<String, String> params = Maps.newHashMap();
		params.put("request_time", now.toString(DateTimeFormat.forPattern("yyyyMMddHHmmss")));
		params.put("trade_code", "001");
		params.put("channel_id", cid);
		params.put("order_id", investCrowdResult.getId());
		params.put("amount", String.valueOf(amount));
		params.put("merchant_id", "MFL_CROWD_20210001");// 众筹订单也是属于美疯啦渠道，所以还是要给一个merchant_id，我们约定一个特殊商户号，用来做众筹的结算

		try {
			params.put("merchant_name", URLEncoder.encode("美疯啦金服", "UTF-8"));
			params.put("description", URLEncoder.encode(investCrowdLimit.getCrowdName(), "UTF-8"));
		} catch (UnsupportedEncodingException e) {

		}
		// TODO:
		params.put("notify_url", snpc + "/v1/core/investCrowd/notify");
		// params.put("return_url", API.getHost() +
		// "/v1/core/investCrowd/return");
		params.put("return_url", returnURL);
		// params.put("ext_data", "");
		params.put("trade_time", now.toString(DateTimeFormat.forPattern("yyyyMMddHHmmss")));
		// params.put("expiry_time", "");
		params.put("mobile", mobile);

		// TODO:上线时改为正式Key
		String PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDUBpzutmxJlr1sO7XraszmdRIaFJLAq8cOqZbd+ciOBytES1ZSkZwa0jGkSUP1SGynev2T+fTVEyc2IXr/vKEepuwY+6zI/3ir+px2nnc3vwhdhfw5+tKWdrNZr6HHTGYolYq6bKd4E5lb2hV1alkVbpNw7FM5ESZpZa8rChDEywIDAQAB";

		X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.decodeBase64(PUBLIC_KEY));
		try {
			KeyFactory factory = KeyFactory.getInstance("RSA");
			Key publicKey = factory.generatePublic(keySpec);
			Cipher cipher = Cipher.getInstance("RSA");
			cipher.init(Cipher.ENCRYPT_MODE, publicKey);

			byte[] data = new ObjectMapper().writeValueAsString(params).getBytes();

			byte[] buffer = null;

			for (int i = 0; i < data.length; i += 64) {
				byte[] doFinal = cipher.doFinal(ArrayUtils.subarray(data, i, i + 64));
				buffer = ArrayUtils.addAll(buffer, doFinal);

			}

			String param = Base64.encodeBase64String(buffer);
			// result.put("ppp", param);
			result.put("pay_url", snpc + "/v1/ibp/payment/h5.html?param=" + param);

		} catch (Exception e) {
			e.printStackTrace();
		}
		return result;
	}

	@RequestMapping("investCrowd/notify")
	@ResponseBody
	public String notify(HttpServletRequest request, HttpServletResponse response) {
		response.setHeader("Access-Control-Allow-Origin", "*");
		String orderId = request.getParameter("order_id");
		Double amount = Double.parseDouble(request.getParameter("amount"));
		String channelId = request.getParameter("channel_id");
		String pay_time = request.getParameter("pay_time");
		String tradeCode = request.getParameter("trade_code");
		String code = request.getParameter("code");

		if (ResultCode.SUCCESS.equalsIgnoreCase(code)) {
			// 更新付款状态
			InvestCrowd investCrowd = investCrowdService.get(orderId);
			investCrowd.setPayStatus(1);
			// 序列码12位
			String snCode = StringUtils.getRandomNumberString(12);
			investCrowd.setSnCode(snCode);
			investCrowdService.save(investCrowd);

			// 更新 数量
			InvestCrowdLimit investCrowdLimit = investCrowdLimitService.findByCrowdNo(investCrowd.getCrowdNo());
			int count = investCrowdLimit.getCount();
			int balance = investCrowdLimit.getBalance();
			int crowdLevel = investCrowd.getCrowdLevel();
			investCrowdLimit.setCount(count + crowdLevel);
			investCrowdLimit.setBalance(balance - crowdLevel);
			investCrowdLimitService.save(investCrowdLimit);

			Account account = MemberUtils.getAccount(investCrowd.getMemberId());
			accountManager.deposit(account, channelId, amount, NotesBook.TYPE_DEPOSIT, "众筹", RZContents.DEFAULT_PAYMENT_CHANNEL_ID, orderId);
			accountManager.transferOut(account, channelId, amount, NotesBook.TYPE_CROWD, "众筹");

			// 发送短信
			String mobile = memberSecurityService.get(investCrowd.getMemberId()).getMobile();
			SMSClient.sendRedeemCode(mobile, amount, investCrowd.getExpectReturn(), snCode);

		}
		return "success";
	}
}
